/*
 * mysql_test.c
 *
 *  Created on: 2018年3月23日
 *      Author: yaoqiaobing
 */
#include "../../../include/test/lib_acl/mysql_test.h"

#include "lib_acl.h"
#include "mysql.h"
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

static ACL_DB_POOL *__db_pool = NULL;

static int db_before_connect(ACL_DB_HANDLE* db_handle, void *ctx acl_unused)
{
	const char *myname = "db_before_connect";
	MYSQL *mysql;

	acl_msg_info("%p\n", (void*) db_handle);
	mysql = (MYSQL*) acl_dbpool_export(db_handle);
	if (mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "GB2312")) {
		acl_msg_error("%s: mysql_options error\n", myname);
		return (-1);
	}

	acl_msg_info("%s: ok\n", myname);
	return (0);
}

static int db_after_connect(ACL_DB_HANDLE* db_handle, void *ctx acl_unused)
{
	const char *myname = "db_after_connect";

	(void) db_handle;
	acl_msg_info("%s: ok\n", myname);
	return (0);
}

static void dbpool_init(const char *addr, const char *name, const char *usr,
	const char *pass, int dbpool_max, int dbping, int dbtimeout)
{
	const char *myname = "dbconn_init";

	// 1.构造db_info对象
	ACL_DB_INFO db_info;
	memset(&db_info, 0, sizeof(ACL_DB_INFO));
	ACL_SAFE_STRNCPY(db_info.db_addr, addr, sizeof(db_info.db_addr));
	ACL_SAFE_STRNCPY(db_info.db_name, name, sizeof(db_info.db_name));
	ACL_SAFE_STRNCPY(db_info.db_user, usr, sizeof(db_info.db_user));
	ACL_SAFE_STRNCPY(db_info.db_pass, pass, sizeof(db_info.db_pass));

	db_info.db_max = dbpool_max;                    // 连接池最大句柄空间
	db_info.ping_inter = dbping;
	db_info.timeout_inter = dbtimeout;
	db_info.auto_commit = 1;                        // ******自动提交******

	db_info.db_before_connect = db_before_connect;  // 句柄打开连接前执行，例如设置字符集
	db_info.db_after_connect = db_after_connect;    // 句柄断开连接后执行

	// 2.创建一个mysql数据库连接池
	__db_pool = acl_dbpool_create("mysql", &db_info);
	if (__db_pool == NULL)
		acl_msg_fatal("%s(%d): init db pool error", myname, __LINE__);
}

static ACL_DB_HANDLE *dbpool_get(void)
{
	const char *myname = "dbconn_get";
	ACL_DB_HANDLE *db_handle;

	if (__db_pool == NULL)
		acl_msg_fatal("%s(%d): db pool null", myname, __LINE__);

	// 从连接池中获取一个连接句柄(状态变为ACL_DBH_STATUS_INUSE)
	db_handle = acl_dbpool_peek(__db_pool);
	if (db_handle == NULL) {
		acl_msg_error("%s(%d): get db conn error", myname, __LINE__);
		return (NULL);
	}

	return (db_handle);
}

static void dbpool_put(ACL_DB_HANDLE *db_handle)
{
	const char *myname = "dbconn_put";

	if (db_handle == NULL)
		acl_msg_fatal("%s(%d): input null", myname, __LINE__);

	acl_dbpool_release(db_handle);
}

static void dbpool_free(void)
{
	if (__db_pool) {
		acl_dbpool_destroy(__db_pool);
		__db_pool = NULL;
	}
}

int walk_fn(const void** result_row, void *arg) {
	ACL_DB_HANDLE* db_handle = (ACL_DB_HANDLE*) arg;
	printf("db_name: [%s], table_name: [%s]\n", db_handle->parent->db_info.db_name, (char*)*result_row);
	return 0;
}

static void dbsql_table(ACL_DB_HANDLE *db_handle) {
	int error = 0;
	acl_dbsql_results(db_handle, "show tables;", &error, walk_fn, db_handle);
}

static void dbsql_select(ACL_DB_HANDLE *db_handle) {
	int error = 0;

	// 1.查询
	ACL_SQL_RES* res = acl_dbsql_select(db_handle, "select * from upyk_sequence;", &error);

	// 2.输出列名
	printf("line: %5d", 0);
	for (int i = 0; i < res->fields_num; i++) {
		printf("%50s", (res->fields)[i]);
	}
	printf("\n");

	// 3.遍历每一行记录
	ACL_ITER iter;
	ACL_FOREACH(iter, res)
	{
		printf("line: %5d", iter.i);
		for (int i = 0; i < res->fields_num; i++) {
			printf("%50s", ((char **) iter.ptr)[i]);
		}
		printf("\n");
	}

	// 4.释放sql查询结果集
	acl_dbsql_free_result(db_handle, res);
}

static void dbsql_update(ACL_DB_HANDLE *db_handle, const char *sql_str) {
	printf("sql_str is [%s]\n", sql_str);

	int error = 0;

	int affectRows = acl_dbsql_update(db_handle, sql_str, &error);
	if (affectRows >= 0) {
		printf("affect rows is %d\n", affectRows);
	} else {
		printf("fail to exec sql, error is %d\n", error);
	}
}

static void usage(const char *procname)
{
	acl_msg_info("usage: %s -h[help] -H mysql_addr -N dbname -U dbuser -P dbpass\n", procname);
}

/**
 * 注意在ACL库的MYSQL操作C版本上，没有提供事务控制的机制，必须设置db_info.auto_commit = 1; // ******自动提交******
 */
int mysql_test(int argc, char *argv[]) {
	// ----------------------参数-------------------------
	ACL_ARGV* acl_argv = acl_argv_split("mysql_test -H 116.196.78.242:3306 -N db_admin -U root -P 123456", " ");
	argc = acl_argv->argc;
	argv = acl_argv->argv;
	// ----------------------参数-------------------------

	ACL_DB_HANDLE *db_handle;
	char  db_addr[256], db_name[256], db_user[256], db_pass[256];
	int   db_max = 10, db_ping = 60, db_timeout = 60;
	int   ch;

	db_addr[0] = 0;
	db_name[0] = 0;
	db_user[0] = 0;
	db_pass[0] = 0;

	while ((ch = getopt(argc, argv, "hH:N:U:P:")) > 0) {
		switch (ch) {
		case 'h':
			usage(argv[0]);
			return (0);
		case 'H':
			snprintf(db_addr, sizeof(db_addr), "%s", optarg);
			break;
		case 'N':
			snprintf(db_name, sizeof(db_name), "%s", optarg);
			break;
		case 'U':
			snprintf(db_user, sizeof(db_user), "%s", optarg);
			break;
		case 'P':
			snprintf(db_pass, sizeof(db_pass), "%s", optarg);
			break;
		default:
			break;
		}
	}

	if (db_addr[0] == 0 || db_name[0] == 0 || db_user[0] == 0 || db_pass[0] == 0) {
		usage(argv[0]);
		return (1);
	}

	// 1.初始化数据库连接池
	dbpool_init(db_addr, db_name, db_user, db_pass, db_max, db_ping, db_timeout);
	acl_msg_info("dbpool_init ok\n");

	// 2.从连接池中获取一个连接句柄(状态变为ACL_DBH_STATUS_INUSE)
	db_handle = dbpool_get();
	if (db_handle) {
		acl_msg_info("dbpool_get ok\n");

		printf("\n---------------dbsql_table---------------\n");
		dbsql_table(db_handle);

		printf("\n---------------dbsql_select---------------\n");
		dbsql_select(db_handle);

		printf("\n---------------dbsql_insert---------------\n");
		dbsql_update(db_handle, "insert into upyk_sequence(seq_tablename, seq_val, seq_current_value, seq_increment, seq_add_name, seq_add_time) values('upyk_course', 'seq_course_id', 100, 1, NULL, NULL);");

		printf("\n---------------dbsql_select---------------\n");
		dbsql_select(db_handle);

		printf("\n---------------dbsql_update---------------\n");
		dbsql_update(db_handle, "update upyk_sequence set seq_tablename = 'upyk_class' where seq_tablename = 'upyk_course';");

		printf("\n---------------dbsql_select---------------\n");
		dbsql_select(db_handle);

		printf("\n---------------dbsql_delete---------------\n");
		dbsql_update(db_handle, "delete from upyk_sequence where seq_tablename = 'upyk_class';");

		printf("\n---------------dbsql_select---------------\n");
		dbsql_select(db_handle);

		// 3.将连接句柄还给连接池(状态变为ACL_DBH_STATUS_READY)
		dbpool_put(db_handle);
		acl_msg_info("dbpool_put ok\n");
	}

	// 4.释放连接池对象
	dbpool_free();
	acl_msg_info("dbpool_free ok\n");

	// ----------------------参数-------------------------
	acl_argv_free(acl_argv);
	// ----------------------参数-------------------------

	return (0);
}


